package demo.ui;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class GameCanvas extends Canvas{

	private static final long serialVersionUID = 1L;
	private static final int FPS = 25;
	
	private int bufferWidth;
    private int bufferHeight;
    private Image bufferImage;
    private Graphics bufferGraphics;
    private boolean running = false;
	
	private AffineTransform transform = new AffineTransform();
	private Tank tank = new Tank();
	private RenderRunner runner = new RenderRunner();
	
	public GameCanvas(){
		tank.x = 100;
		tank.y = 100;
		tank.setDirection(1.45f);
		
		try{
			tank.image = ImageIO.read(new File("D:\\Projects\\workspace\\my-tank-game\\resources\\tank.png"));
		}catch(Exception ex){
			ex.printStackTrace();
		}
		
		this.addComponentListener(new ComponentListener() {
			
			@Override
			public void componentShown(ComponentEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void componentResized(ComponentEvent arg0) {
				running = false;
				// TODO Auto-generated method stub
				// always keep track of the image size
		        bufferWidth=getSize().width;
		        bufferHeight=getSize().height;

		        //    clean up the previous image
		        if(bufferGraphics!=null){
		            bufferGraphics.dispose();
		            bufferGraphics=null;
		        }
		        if(bufferImage!=null){
		            bufferImage.flush();
		            bufferImage=null;
		        }
		        System.gc();

		        //    create the new image with the size of the panel
		        bufferImage=createImage(bufferWidth,bufferHeight);
		        bufferGraphics=bufferImage.getGraphics();
		        running = true;
		        Thread thread = new Thread(runner);
				thread.start();
			}
			
			@Override
			public void componentMoved(ComponentEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void componentHidden(ComponentEvent arg0) {
				// TODO Auto-generated method stub
				running = false;
			}
		});
		
		setPreferredSize(new Dimension(500, 300));
	}

	public void paint(Graphics g){
		paintFrame();
		//we finaly paint the offscreen image onto the onscreen image
        g.drawImage(bufferImage,0,0,this);
	}
	
	private void paintFrame(){
		Graphics2D g2 = (Graphics2D)bufferGraphics;
		g2.clearRect(0,0,bufferWidth,bufferHeight);
		transform.setToIdentity();
		transform.translate(tank.x-tank.image.getWidth(null)/2, tank.y-tank.image.getHeight(null)/2);
		//rotate
		g2.drawImage(tank.image, transform, null);
	}
	
	
	public void update(){
		/*
		if(tank.x<=0 || tank.y >= this.getWidth())
			tank.vx = -tank.vx;
		
		if(tank.y<=0 || tank.y >= this.getHeight())
			tank.vy = -tank.vy;
		
		tank.x += tank.vx;
		tank.y += tank.vy;
		*/
	}
	
	class RenderRunner implements Runnable{

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(running){
				update();
				repaint();
				try{
					Thread.sleep(1000/FPS);
				}catch(InterruptedException ie){}
			}
		}
		
	}
}

class Tank{
	public volatile float x;
	public volatile float y;
	private float vx, vy;
	private float direction;
	private int speed;
	public float vd;
	public Image image;
	private boolean moving = false;
	private Thread thread = null;
	private ObjectRunner objRuner = new ObjectRunner();
	private int sleepingTime = 70;
	public Tank(){
		try {
			image = ImageIO.read(new File("D:\\Projects\\workspace\\my-tank-game\\resources\\tank.png"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void setDirection(float dir){
		direction = dir;
		vy = (float)(Math.sin(direction));
		vx = (float)(Math.cos(direction));
	}
	
	public float getDirection(){
		return direction;
	}
	
	public void setSpeed(int spd){
		this.speed = spd;
		sleepingTime = 1000/speed;
	}
	
	public int getSpeed(){
		return speed;
	}
	
	public void draw(Graphics2D g2, AffineTransform transform){
		transform.setToIdentity();
		transform.translate(x - image.getWidth(null)/2, y-image.getHeight(null)/2);
		transform.rotate(direction);
		//rotate
		g2.drawImage(image, transform, null);
	}
	
	public void startMove() throws InterruptedException{
		if(thread != null && thread.isAlive()){
			moving = false;
			thread.join();
			thread = null;
		}
		
		moving = true;
		thread = new Thread(objRuner);
		thread.start();
	}
	
	private void move(){
		x += vx;
		y += vy;
		
		if(x < 0 || y < 0)
			moving = false;
	}
	
	public void stop() throws InterruptedException{
		moving = false;
		if(thread != null && thread.isAlive())
			thread.join();
	}
	
	public boolean isMoving(){
		return moving;
	}
	
	class ObjectRunner implements Runnable{
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(moving){
				try {
					//TODO: calculate the speed of object.
					//Scaling the world and find out the sleeping time
					move();
					Thread.sleep(sleepingTime);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
